﻿#region Copyright Information
// // ****************************************************************
// // Feel free to extend or modify the code of the application to your needs. 
// // But remember do it for the Glory of our Lord Jesus Christ
// // ****************************************************************
#endregion
#region Usings

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Data.Configuration;
using Interfaces.Configuration;
using NLog;

#endregion

namespace Core.Configuration
{
    /// <summary>
    /// Holds information regarding the configuration section.
    /// </summary>
    public class ConfigurationManager : IConfigurationManager
    {
        /// <summary>
        /// Reference to logging tool.
        /// </summary>
        private static readonly Logger logging = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// Holds configuration file.
        /// </summary>
        private readonly XDocument configuration;

        /// <summary>
        /// Constructor for <see cref="ConfigurationManager"/> class.
        /// </summary>
        /// <param name="configPath">The path to the configuration file.</param>
        public ConfigurationManager(string @configPath)
        {
            // Load the configuration file.
            configuration = XDocument.Load(configPath);

            logging.Info("Load the configuration file.");
        }

        #region Implementation of IConfigurationManager

        /// <summary>
        /// Add a item to the configuration file.
        /// </summary>
        /// <param name="item">The configuration item.</param>
        public void AddItem(ConfigurationItem item)
        {
            var element = new XElement("item");
            element.SetAttributeValue("name", item.Name);
            element.SetAttributeValue("value", item.Value);
            configuration.Root.Add(element);

            logging.Info(string.Format("Add {0} with value {1} in the config file.", item.Name, item.Value));
        }

        /// <summary>
        /// Deletes a item by name.
        /// </summary>
        /// <param name="name">The name of the item.</param>
        public void DeleteItem(string name)
        {
            configuration.Root
                .Descendants()
                .Where(element => element.Attribute("name").Value == name)
                .Remove();

            logging.Info(string.Format("Delete {0} from the config file.", name));
        }

        /// <summary>
        /// Update the specified item.
        /// </summary>
        /// <param name="item">The configuration item.</param>
        public void UpdateItem(ConfigurationItem item)
        {
            configuration.Root.Descendants()
                .First(element => element.Attribute("name").Value == item.Name)
                .SetAttributeValue("value", item.Value);

            logging.Info(string.Format("Update {0} with value {1} in the config file.", item.Name, item.Value));
        }

        /// <summary>
        /// Return an item with the specified name.
        /// </summary>
        /// <param name="name">The name of the configuration item.</param>
        /// <returns>Configuration item.</returns>
        public ConfigurationItem GetItem(string name)
        {
            // Retrieve the item with the following name.
            XElement item = configuration.Root.Descendants().First(element => element.Attribute("name").Value == name);
            // Build the custom configuration item.
            return new ConfigurationItem(item.Attribute("name").Value, item.Attribute("value").Value);
        }

        /// <summary>
        /// Returns all the items in the configuration file.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ConfigurationItem> GetAllItems()
        {
            return from item in configuration.Root.Descendants()
                   select new ConfigurationItem(item.Attribute("name").Value, item.Attribute("value").Value);
        }

        /// <summary>
        /// Save the configuration file to disk.
        /// </summary>
        /// <param name="filePath">The path to save the file.</param>
        public void Save(string @filePath)
        {
            try
            {
                configuration.Save(filePath);

                logging.Info(string.Format("Save the config file to {0}", filePath));
            }
            catch (Exception ex)
            {
                logging.Error(string.Format("{0} exception accured", ex.Message));
            }
        }

        #endregion
    }
}